package tt.dz.egobus.servicemanager.entities;

import com.alibaba.fastjson.JSONObject;
import org.hibernate.annotations.*;
import org.hibernate.validator.constraints.NotEmpty;
import tt.dz.egobus.api.managerservice.manager.BusinessBaseLimitStatus;
import tt.dz.egobus.base.entity.BaseEntity;
import tt.dz.egobus.bean.BusinessStatus;
import tt.dz.egobus.servicemanager.base.dialect.ServiceManagerJsonbType;
import tt.dz.egobus.servicemanager.business.convert.BusServiceViewCornConvert;
import tt.dz.egobus.servicemanager.vo.BusServiceViewVo;
import tt.dz.egobus.vo.KV;

import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Anson
 * @date 17-3-27
 * @name 业务行程详细表
 * @since 1.0.3
 */
@Entity
@Table(name = "business_service_info", schema = "servicemanager")
@NamedQueries(value = {@NamedQuery(name = "getDriverLastestInfo", query = "   from BusinessServiceInfo t   " +
        "where  1=1     and t.businessService.isValidate=true  and   t.businessService.driverId=:driverId   " +
        "   order  by  t.createTime desc  "),
        @NamedQuery(name = "getBusinessServiceInfoByBusinessIds", query = "    from  BusinessServiceInfo t   where  1=1  " +
                "  and t.isValidate=true  and   t.businessId in  (:businessId)     order  by  t.createTime desc  "),
        @NamedQuery(name = "isContainerDriverBespeakDate", query = " select  count(t.id)  from BusinessServiceInfo t   " +
                " where 1=1  and t.businessService.driverId=:driverId and t.businessService.status =:status " +
                "   and to_char(t.bespeakTime,'YYYY-MM-DD') in (:bespeakTime) ")})
@TypeDef(name = "JsonBType", typeClass = ServiceManagerJsonbType.class)
public class BusinessServiceInfo extends BaseEntity {

    private static final long serialVersionUID = -8322106559616294928L;

    public static final KV<String, String> BUS_SERVICE_ALIAS = new KV<>("bs", "businessService");

    static {
        List<KV<String, String>> aliaseList = new ArrayList<KV<String, String>>(1);
        aliaseList.add(BUS_SERVICE_ALIAS);
        BusinessServiceInfo.ALIAS_LIST.put(BusinessServiceInfo.class, aliaseList);
    }


    @Column(name = "business_service_id")
    @NotEmpty(message = "业务主键id不能为空")
    private String businessServiceId;

    /**
     * 服务主表
     */
    @ManyToOne(targetEntity = BusinessService.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "business_service_id", insertable = false, updatable = false)
    @Fetch(FetchMode.JOIN)
    private BusinessService businessService;

    /**
     * 业务流水号 且是1:1的关系
     */
    @Column(name = "business_id", unique = true)
    @NotEmpty(message = "当前业务流水号不能为空")
    private String businessId;

    @Column(name = "bus_id")
    @NotEmpty(message = "业务当前车id不能为空")
    private String busId;

    /**
     * 当前行程数单位M
     */
    @Column(name = "distance", precision = 18, scale = 6)
    private double distance;


    /**
     * 接单起点经度
     */
    @Column(name = "accept_x", precision = 18, scale = 10)
    @Min(value = 0L, message = "接单坐标的经度不能小于0")
    @Max(value = 360L, message = "接单坐标的经度不能大于360")
    private double acceptX;

    /**
     * 接单起点纬度
     */
    @Column(name = "accept_y", precision = 18, scale = 10)
    @Min(value = 0L, message = "接单坐标的纬度不能小于0")
    @Max(value = 180L, message = "接单坐标的纬度不能大于180")
    private double acceptY;

    /**
     * 行程起点经度
     */
    @Column(name = "start_x", precision = 18, scale = 10)
    @Min(value = 0L, message = "开始坐标的经度不能小于0")
    @Max(value = 360L, message = "开始坐标的经度不能大于360")
    private double startX;

    /**
     * 行程起点纬度
     */
    @Column(name = "start_y", precision = 18, scale = 10)
    @Min(value = 0L, message = "开始坐标的纬度不能小于0")
    @Max(value = 180L, message = "开始坐标的纬度不能大于180")
    private double startY;

    /**
     * 行程开始地点
     */
    @Column(name = "start_address")
    private String startAddress;
    /**
     * 行程结束经度
     */
    @Column(name = "end_x", precision = 18, scale = 10)
    @Min(value = 0L, message = "结束坐标的经度不能小于0")
    @Max(value = 360L, message = "结束坐标的经度不能大于360")
    private double endX;

    /**
     * 行程结束纬度
     */
    @Column(name = "end_y", precision = 18, scale = 10)
    @Min(value = 0L, message = "结束坐标的纬度不能小于0")
    @Max(value = 180L, message = "结束坐标的纬度不能大于180")
    private double endY;

    /**
     * 行程结束地点
     */
    @Column(name = "end_address")
    private String endAddress;

    /**
     * 是否失效
     */
    @Column(name = "is_validate")
    private boolean isValidate;


    /**
     * 创建时间
     */
    @Column(name = "create_time")
    private Date createTime;


    /**
     * 结束时间
     */
    @Column(name = "end_time")
    private Date endTime;

    /**
     * 用户请求的开始地址
     */
    @Column(name = "request_start_address")
    private String requestStartAddress;

    /**
     * 用户请求开始的x,经度
     */
    @Column(name = "request_start_x")
    @Min(value = 0L, message = "用户请求开始经度不能小于0")
    @Max(value = 360L, message = "用户请求开始经度不能大于360")
    private double requestStartX;

    /**
     * 用户请求开始的y,纬度
     */
    @Column(name = "request_start_y")
    @Min(value = 0L, message = "用户请求开始纬度不能小于0")
    @Max(value = 180L, message = "用户请求开始不能大于180")
    private double requestStartY;

    /**
     * 用户请求的结束地址
     */
    @Column(name = "request_end_address")
    private String requestEndAddress;

    /**
     * 用户请求结束的x,经度
     */
    @Column(name = "request_end_x")
    @Min(value = 0L, message = "用户请求结束经度不能小于0")
    @Max(value = 360L, message = "用户请求结束经度不能大于360")
    private double requestEndX;

    /**
     * 用户请求结束的y,纬度
     */
    @Column(name = "request_end_y")
    @Min(value = 0L, message = "用户请求结束纬度不能小于0")
    @Max(value = 180L, message = "用户请求结束纬度不能大于180")
    private double requestEndY;

    //--------------------新增字段 2017年08月25日16:14:28 --------------------------//


    /**
     * 司机真实姓名
     */
    @Column(name = "driver_name")
    private String driverName;


    /**
     * 司机手机号码
     **/
    @Column(name = "phone_number")
    private String phoneNumber;

    /**
     * 预约时间,若当前是预约类别,则当前预约时间不能空
     */
    @Column(name = "bespeak_time")
    private Date bespeakTime;

    /**
     * 乘客上车时间
     */
    @Column(name = "boarding_time")
    private Date boardingTime;

    /**
     * 请求人名称
     */
    @Column(name = "user_name")
    private String userName;

    /**
     * 请求人手机
     */
    @Column(name = "user_phone")
    private String userPhone;

    /**
     * 乘车人名称
     */
    @Column(name = "passenger_name")
    private String passengerName;

    /**
     * 乘车人手机
     */
    @Column(name = "passenger_phone")
    private String passengerPhone;

    /**
     * 超时的时间
     * 单位秒
     */
    @Column(name = "orver_time_seconds")
    @ColumnDefault(value = "0")
    private double orverTimeSeconds;


    /**
     * 当前产品类别序列化
     */
    @Column(name = "bus_serice_info", columnDefinition = "jsonb default null")
    @Type(type = "JsonBType")
    private JSONObject busSericeInfo;

    private transient BusServiceViewCornConvert busServiceViewCornConvert = new BusServiceViewCornConvert();

    /**
     * @author Anson
     * @date 17-8-25
     * @name 将产品信息log化的信息反向生成为一个view
     * @since 1.0.6
     */
    public BusServiceViewVo convertBusService() {
        return busServiceViewCornConvert.convertCornB().convert(this.busSericeInfo);
    }

    public void putBusServiceInfoJsonObject(BusServiceViewVo busServiceViewVo) {
        this.setBusSericeInfo(busServiceViewCornConvert.convertCornA().convert(busServiceViewVo));
    }

    /**
     * @author Anson
     * @date 17-9-2
     * @name 计算当前超时相关信息
     * @since 1.0.7
     */
    public BusinessBaseLimitStatus getLimitStatus() {
        BusServiceViewVo busService = this.convertBusService();
        Date boardingTimeBack = this.getBoardingTime();
        // 单位毫秒
        if (null == boardingTimeBack) {
            return new BusinessBaseLimitStatus();
        }
        Long boardingTime = boardingTimeBack.getTime();
        // 当前时间，单位：毫秒
        //默认是当前时间,若存在结束时间则以结束时间为准
        Long now = System.currentTimeMillis();
        Long endTime = now;
        Date businessEndTime = this.getEndTime();
        if (businessEndTime != null) {
            endTime = businessEndTime.getTime();
        }
        BusinessBaseLimitStatus limitStatus = new BusinessBaseLimitStatus();
        // 限制时间单位：毫秒
        Long timeLimit = Long.valueOf(busService.getTimeLimit()) * 60 * 1000;
        // 超时时间单位：秒
        Long overBaseTimeLimtSeconds = (endTime - boardingTime - timeLimit) / 1000;
        if (overBaseTimeLimtSeconds.compareTo(0L) > 0) {
            // 超时
            limitStatus.setOverBaseTimeLimit(true);
            limitStatus.setOverBaseTimeLimtSeconds(overBaseTimeLimtSeconds);
        } else {
            // 未超时，剩余时间
            long retainBaseTimeLimitSeconds = (boardingTime + timeLimit - endTime) / 1000;
            limitStatus.setRetainBaseTimeLimitSeconds(retainBaseTimeLimitSeconds);
        }
        limitStatus.setCurrentTime(now);
        return limitStatus;
    }

    /**
     * @return true : 允许取消 false:不允许取消
     * @author Anson
     * @date 17-9-1
     * @name 当前司机是否允许(未接到乘客, 司机已经去接人, 乘客一直联系不到)取消行程
     * @since 1.0.7
     */
    public boolean businessCanAbleDriverCancel() {
        return BusinessStatus.assertBeginBusiness(this.businessService.getStatus());
    }

    public boolean getIsValidate() {
        return isValidate;
    }

    public void setIsValidate(boolean validate) {
        isValidate = validate;
    }

    public boolean isValidate() {
        return isValidate;
    }

    public void setValidate(boolean validate) {
        isValidate = validate;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }

    public String getBusinessId() {
        return businessId;
    }

    public void setBusinessId(String businessId) {
        this.businessId = businessId;
    }

    public String getBusId() {
        return busId;
    }

    public void setBusId(String busId) {
        this.busId = busId;
    }

    public double getDistance() {
        return distance;
    }

    public void setDistance(double distance) {
        this.distance = distance;
    }

    public double getStartX() {
        return startX;
    }

    public void setStartX(double startX) {
        this.startX = startX;
    }

    public double getStartY() {
        return startY;
    }

    public void setStartY(double startY) {
        this.startY = startY;
    }

    public double getEndX() {
        return endX;
    }

    public void setEndX(double endX) {
        this.endX = endX;
    }

    public double getEndY() {
        return endY;
    }

    public void setEndY(double endY) {
        this.endY = endY;
    }

    public String getBusinessServiceId() {
        return businessServiceId;
    }

    public void setBusinessServiceId(String businessServiceId) {
        this.businessServiceId = businessServiceId;
    }

    public BusinessService getBusinessService() {
        return businessService;
    }

    public void setBusinessService(BusinessService businessService) {
        this.businessService = businessService;
    }

    public double getAcceptX() {
        return acceptX;
    }

    public void setAcceptX(double acceptX) {
        this.acceptX = acceptX;
    }

    public double getAcceptY() {
        return acceptY;
    }

    public void setAcceptY(double acceptY) {
        this.acceptY = acceptY;
    }

    public String getStartAddress() {
        return startAddress;
    }

    public void setStartAddress(String startAddress) {
        this.startAddress = startAddress;
    }

    public String getEndAddress() {
        return endAddress;
    }

    public void setEndAddress(String endAddress) {
        this.endAddress = endAddress;
    }

    public String getRequestStartAddress() {
        return requestStartAddress;
    }

    public void setRequestStartAddress(String requestStartAddress) {
        this.requestStartAddress = requestStartAddress;
    }

    public double getRequestStartX() {
        return requestStartX;
    }

    public void setRequestStartX(double requestStartX) {
        this.requestStartX = requestStartX;
    }

    public double getRequestStartY() {
        return requestStartY;
    }

    public void setRequestStartY(double requestStartY) {
        this.requestStartY = requestStartY;
    }

    public String getRequestEndAddress() {
        return requestEndAddress;
    }

    public void setRequestEndAddress(String requestEndAddress) {
        this.requestEndAddress = requestEndAddress;
    }

    public double getRequestEndX() {
        return requestEndX;
    }

    public void setRequestEndX(double requestEndX) {
        this.requestEndX = requestEndX;
    }

    public double getRequestEndY() {
        return requestEndY;
    }

    public void setRequestEndY(double requestEndY) {
        this.requestEndY = requestEndY;
    }

    public String getDriverName() {
        return driverName;
    }

    public void setDriverName(String driverName) {
        this.driverName = driverName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Date getBespeakTime() {
        return bespeakTime;
    }

    public void setBespeakTime(Date bespeakTime) {
        this.bespeakTime = bespeakTime;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPhone() {
        return userPhone;
    }

    public void setUserPhone(String userPhone) {
        this.userPhone = userPhone;
    }

    public String getPassengerName() {
        return passengerName;
    }

    public void setPassengerName(String passengerName) {
        this.passengerName = passengerName;
    }

    public String getPassengerPhone() {
        return passengerPhone;
    }

    public void setPassengerPhone(String passengerPhone) {
        this.passengerPhone = passengerPhone;
    }

    public double getOrverTimeSeconds() {
        return orverTimeSeconds;
    }

    public void setOrverTimeSeconds(double orverTimeSeconds) {
        this.orverTimeSeconds = orverTimeSeconds;
    }

    public JSONObject getBusSericeInfo() {
        return busSericeInfo;
    }

    public void setBusSericeInfo(JSONObject busSericeInfo) {
        this.busSericeInfo = busSericeInfo;
    }

    public Date getBoardingTime() {
        return boardingTime;
    }

    public void setBoardingTime(Date boardingTime) {
        this.boardingTime = boardingTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof BusinessServiceInfo)) return false;

        BusinessServiceInfo that = (BusinessServiceInfo) o;
        return this.hashCode() == that.hashCode();
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = businessServiceId != null ? businessServiceId.hashCode() : 0;
        result = 31 * result + (businessService != null ? businessService.hashCode() : 0);
        result = 31 * result + (businessId != null ? businessId.hashCode() : 0);
        result = 31 * result + (busId != null ? busId.hashCode() : 0);
        temp = Double.doubleToLongBits(distance);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(acceptX);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(acceptY);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(startX);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(startY);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (startAddress != null ? startAddress.hashCode() : 0);
        temp = Double.doubleToLongBits(endX);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(endY);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (endAddress != null ? endAddress.hashCode() : 0);
        result = 31 * result + (isValidate ? 1 : 0);
        result = 31 * result + (createTime != null ? createTime.hashCode() : 0);
        result = 31 * result + (endTime != null ? endTime.hashCode() : 0);
        result = 31 * result + (requestStartAddress != null ? requestStartAddress.hashCode() : 0);
        temp = Double.doubleToLongBits(requestStartX);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(requestStartY);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (requestEndAddress != null ? requestEndAddress.hashCode() : 0);
        temp = Double.doubleToLongBits(requestEndX);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(requestEndY);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (driverName != null ? driverName.hashCode() : 0);
        result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0);
        result = 31 * result + (bespeakTime != null ? bespeakTime.hashCode() : 0);
        result = 31 * result + (boardingTime != null ? boardingTime.hashCode() : 0);
        result = 31 * result + (userName != null ? userName.hashCode() : 0);
        result = 31 * result + (userPhone != null ? userPhone.hashCode() : 0);
        result = 31 * result + (passengerName != null ? passengerName.hashCode() : 0);
        result = 31 * result + (passengerPhone != null ? passengerPhone.hashCode() : 0);
        temp = Double.doubleToLongBits(orverTimeSeconds);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (busSericeInfo != null ? busSericeInfo.hashCode() : 0);
        result = 31 * result + (busServiceViewCornConvert != null ? busServiceViewCornConvert.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "BusinessServiceInfo{" + "businessServiceId='" + businessServiceId + '\'' + ", businessService=" +
                businessService + ", businessId='" + businessId + '\'' + ", busId='" + busId + '\'' + ", distance=" +
                distance + ", acceptX=" + acceptX + ", acceptY=" + acceptY + ", startX=" + startX + ", startY=" +
                startY + ", startAddress='" + startAddress + '\'' + ", endX=" + endX + ", endY=" + endY + ", " +
                "endAddress='" + endAddress + '\'' + ", isValidate=" + isValidate + ", createTime=" + createTime + "," +
                "" + "" + "" + "" + " endTime=" + endTime + ", requestStartAddress='" + requestStartAddress + '\'' +
                ", " + "requestStartX=" + requestStartX + ", requestStartY=" + requestStartY + ", " +
                "requestEndAddress='" + requestEndAddress + '\'' + ", requestEndX=" + requestEndX + ", requestEndY="
                + requestEndY + ", " + "driverName='" + driverName + '\'' + ", phoneNumber='" + phoneNumber + '\'' +
                ", bespeakTime=" + bespeakTime + ", " + "boardingTime=" + boardingTime + ", userName='" + userName +
                '\'' + ", " + "userPhone='" + userPhone + '\'' + ", passengerName='" + passengerName + '\'' + ", " +
                "passengerPhone='" + passengerPhone + '\'' + "," + " orverTimeSeconds=" + orverTimeSeconds + ", " +
                "busSericeInfo=" + busSericeInfo + ", " + "busServiceViewCornConvert=" + busServiceViewCornConvert +
                '}';
    }
}
